#include <iostream>
#include <string>
#include <unistd.h>
// #include <pthread.h>
#include "Thread.hpp"
#include "lockGuard.hpp"

using namespace std;

int tickets = 1000;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 可以不用pthread_mutex_init，这是我在外部定义的锁

void threadRoutine(void *args)
{
    std::string message = static_cast<const char *>(args);
    while (true)
    {
        // pthread_mutex_lock(&mutex); // 所有线程都要在访问前加锁，所以线程都要遵循这个规则

        {                                // 花括号里自动完成加锁和解锁
            LockGuard lockguard(&mutex); // RAII 风格的锁

            if (tickets > 0) // 多个线程同时进来，都在--，所以会导致票数会抢到负数
            {
                usleep(2000);                                              // 模拟抢票花费的时间
                cout << message << " get a ticket: " << tickets-- << endl; // 临界区，要对临界区进行加锁
            }
            else
            {
                break;
            }
        }

        // 后面还有动作
        // usleep(1000); // 充当抢完一张票，后续动作
    }
}

int main()
{
    Thread t1(1, threadRoutine, (void *)"hellobit1"); // 创建
    Thread t2(2, threadRoutine, (void *)"hellobit2"); // 创建
    Thread t3(2, threadRoutine, (void *)"hellobit1"); // 创建
    Thread t4(3, threadRoutine, (void *)"hellobit2"); // 创建

    t1.run(); // 启动
    t2.run(); // 启动
    t3.run(); // 启动
    t4.run(); // 启动

    t1.join(); // 释放
    t2.join(); // 释放
    t3.join(); // 释放
    t4.join(); // 释放
}

// 用自己的线程封装
//  void threadRun(void *args)
//  {
//      std::string message = static_cast<const char*>(args);
//      int cnt=10;
//      while(cnt)
//      {
//          cout<<"我是一个线程，"<<message<<" ,cnt: "<<cnt--<<endl;
//          sleep(1);
//      }
//  }
//  int main()
//  {
//      Thread t1(1,threadRun,(void*)"hellobit1");//创建
//      Thread t2(2,threadRun,(void*)"hellobit2");//创建

//     cout<<"thread name: "<<t1.threadname()<<" ,thread id: "<<t1.threadid()<<" ,thread status: "<<t1.status()<<endl;
//     cout<<"thread name: "<<t2.threadname()<<" ,thread id: "<<t2.threadid()<<" ,thread status: "<<t2.status()<<endl;

//     t1.run();//启动
//     t2.run();//启动
//     cout<<"thread name: "<<t1.threadname()<<" ,thread id: "<<t1.threadid()<<" ,thread status: "<<t1.status()<<endl;
//     cout<<"thread name: "<<t2.threadname()<<" ,thread id: "<<t2.threadid()<<" ,thread status: "<<t2.status()<<endl;

//     t1.join();//释放
//     t2.join();//释放
//     cout<<"thread name: "<<t1.threadname()<<" ,thread id: "<<t1.threadid()<<" ,thread status: "<<t1.status()<<endl;
//     cout<<"thread name: "<<t2.threadname()<<" ,thread id: "<<t2.threadid()<<" ,thread status: "<<t2.status()<<endl;

//     return 0;
// }

// 细节
// 1、凡是访问同一个临界资源的线程，都要进行加锁保护，而且必须加同一把锁，这个是一个游戏规则，不能有例外
// 2、每一个线程访问临界区之前，得加锁,加锁本质是给临界区加锁,加锁的粒度尽量要细一些
// 3、线程访问临界区的时候，需要先加锁->所以线程都必须要先看到同一把锁->所本身就是公共资源->锁如何保证自己的安全？->加锁和解锁本身就是原子的
// 4、临界区可以是一行代码，可以是一批代码，
// a.线程可能被切换吗？当然可能，不要特殊化加锁和解锁，还有临界区代码
// b.切换会有影响吗？加锁后，临界区的切换会有影响吗？不会，因为在我不在期间，任何人都没有办法进入临界区，因为他无法成功的申请到锁，因为这个锁被我拿走了
// 5、这也正是体现互斥带来的串行化的表现，站在其他线程的角度，对其他线程有意义的状态就是：锁被我申请（持有锁），锁被我释放了（不持有锁），原子性就体现在这里
// 6、解锁的过程也被设计成为原子的
// 7、锁的原理解释

// int tickets = 1000; // 加锁保证共享资源的安全，临界资源
//  pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//可以不用pthread_mutex_init

// class TData
// {
// public:
//     TData(const string &name, pthread_mutex_t *mutex)
//         : _name(name), _pmutex(mutex)
//     {
//     }
//     ~TData()
//     {
//     }

// public:
//     string _name;
//     pthread_mutex_t *_pmutex;
// };

// void *threadRoutine(void *name)
// {
//     TData *td = static_cast<TData *>(name);
//     while (true)
//     {
//         // pthread_mutex_lock(&mutex); // 所有线程都要在访问前加锁，所以线程都要遵循这个规则
//         pthread_mutex_lock(td->_pmutex);//加锁,是一个让不让你通过的策略

//         if (tickets > 0) // 多个线程同时进来，都在--，所以会导致票数会抢到负数
//         {
//             usleep(2000); // 模拟抢票花费的时间
//             cout << td->_name << " get a ticket: " << tickets-- << endl; // 临界区，要对临界区进行加锁

//             // pthread_mutex_unlock(&mutex);//对mutex解锁
//             pthread_mutex_unlock(td->_pmutex);
//         }
//         else
//         {
//             // pthread_mutex_unlock(&mutex); // 解锁
//             pthread_mutex_unlock(td->_pmutex);
//             break;
//         }

//         // 后面还有动作
//         usleep(1000); // 充当抢完一张票，后续动作
//     }
//     return nullptr;
// }

// int main()
// {
//     pthread_mutex_t mutex;
//     pthread_mutex_init(&mutex, nullptr);

//     pthread_t tids[4];
//     int n = sizeof(tids) / sizeof(tids[0]);
//     for (int i = 0; i < n; i++)
//     {
//         char name[64];
//         snprintf(name, 64, "thread--%d", i + 1);
//         TData *td = new TData(name, &mutex);

//         pthread_create(tids + i, nullptr, threadRoutine, td);
//     }
//     for (int i = 0; i < n; i++)
//     {
//         pthread_join(tids[i], nullptr);
//     }

//     pthread_mutex_destroy(&mutex);
//     return 0;
// }